local proto = require "src.kit.core.proto"
local checker = require "src.kit.core.checker"
--------------------------------------------------
-- @file src/kit/core/event/dispatcher.lua
-- @desc event dispatcher
-- @author doooreyn
-- @date 2020.11.14
-- @more lua的事件分发器，不是cc的那套
--------------------------------------------------
local dispatcher = proto.class("dispatcher")

--
-- @method dispatcher.ctor
-- @desc 事件分发构造器
--
function dispatcher:ctor()
    self.__listeners = {}
end

--
-- @method dispatcher.off_all
-- @desc 添加监听事件
-- @param event string 事件名称
-- @param caller function 事件处理回调
--
function dispatcher:on(event, caller)
    checker.expect_type(event, checker.types.string, "event")
    checker.expect_type(caller, checker.types.func, "caller")

    local list = self.__listeners[event]
    if not list then
        list = {}
        self.__listeners[event] = list
    end
    list[tostring(caller)] = caller
    return caller
end

--
-- @method dispatcher.off
-- @desc 解除监听事件
-- @param event string 事件名称
-- @param caller function 事件处理回调
--
function dispatcher:off(event, caller)
    checker.expect_type(caller, checker.types.func, "caller")
    self:off_by_index(event, tostring(caller))
end

--
-- @method dispatcher.off_by_index
-- @desc 解除监听事件
-- @param event string 事件名称
-- @param caller_index string 事件处理回调序列化字符串
--
function dispatcher:off_by_index(event, caller_index)
    checker.expect_type(event, checker.types.string, "event")
    checker.expect_type(caller_index, checker.types.string, "caller_index")

    local list = self.__listeners[event]
    if not list then
        return
    end
    list[caller_index] = nil

    if table.empty(list) then
        self.__listeners[event] = nil
    end
end

--
-- @method dispatcher.off_all
-- @desc 解除所有监听事件
--
function dispatcher:off_all()
    self.__listeners = {}
end

--
-- @method dispatcher.has
-- @desc 是否存在监听事件
-- @param event string 事件名称
-- @return boolean
--
function dispatcher:has(event)
    checker.expect_type(event, checker.types.string, "event")
    return self.__listeners[event] ~= nil
end

--
-- @method dispatcher.off_all
-- @desc 分发事件
-- @param event string 事件名称
-- @param caller function 事件处理回调
--
function dispatcher:fire(event, ...)
    checker.expect_type(event, checker.types.string, "event")

    if not self:has(event) then
        return
    end
    for _, caller in ipairs(self.__listeners[event]) do
        caller(...)
    end
end

return dispatcher
